#!/bin/bash

# LifeVerse Platform 健康检查脚本
# 用于 CI/CD 流水线中的健康检查和监控

set -e

# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/lifeverse/health-check.log"
DEFAULT_TIMEOUT=30
DEFAULT_RETRIES=5

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log() {
    echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE"
}

warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
}

# 显示帮助信息
show_help() {
    cat << EOF
LifeVerse Platform 健康检查脚本

用法: $0 [选项] <环境>

环境:
    dev         开发环境
    test        测试环境
    prod        生产环境

选项:
    -h, --help              显示帮助信息
    -u, --url <URL>         指定健康检查URL
    -t, --timeout <秒>      请求超时时间 (默认30秒)
    -r, --retries <次数>    重试次数 (默认5次)
    -i, --interval <秒>     重试间隔 (默认10秒)
    -v, --verbose           详细输出
    --deep                  深度健康检查
    --json                  JSON格式输出

检查类型:
    basic       基础健康检查 (默认)
    deep        深度健康检查 (包括数据库、Redis等)
    full        完整健康检查 (包括性能指标)

示例:
    $0 prod                                    # 检查生产环境
    $0 --deep test                            # 深度检查测试环境
    $0 --url https://api.lifeverse.com dev   # 指定URL检查
    $0 --json --timeout 60 prod              # JSON输出，60秒超时

EOF
}

# 解析命令行参数
parse_args() {
    ENVIRONMENT=""
    HEALTH_URL=""
    TIMEOUT=$DEFAULT_TIMEOUT
    RETRIES=$DEFAULT_RETRIES
    INTERVAL=10
    VERBOSE=false
    DEEP_CHECK=false
    JSON_OUTPUT=false

    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            -u|--url)
                HEALTH_URL="$2"
                shift 2
                ;;
            -t|--timeout)
                TIMEOUT="$2"
                shift 2
                ;;
            -r|--retries)
                RETRIES="$2"
                shift 2
                ;;
            -i|--interval)
                INTERVAL="$2"
                shift 2
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            --deep)
                DEEP_CHECK=true
                shift
                ;;
            --json)
                JSON_OUTPUT=true
                shift
                ;;
            -*)
                error "未知选项: $1"
                show_help
                exit 1
                ;;
            *)
                if [[ -z "$ENVIRONMENT" ]]; then
                    ENVIRONMENT="$1"
                else
                    error "过多的参数: $1"
                    show_help
                    exit 1
                fi
                shift
                ;;
        esac
    done

    # 验证参数
    if [[ -z "$ENVIRONMENT" ]]; then
        error "必须指定环境"
        show_help
        exit 1
    fi

    if [[ "$ENVIRONMENT" != "dev" && "$ENVIRONMENT" != "test" && "$ENVIRONMENT" != "prod" ]]; then
        error "无效的环境: $ENVIRONMENT"
        exit 1
    fi
}

# 设置环境变量
setup_environment() {
    if [[ -z "$HEALTH_URL" ]]; then
        case $ENVIRONMENT in
            dev)
                HEALTH_URL="https://dev.lifeverse.com/api/actuator/health"
                ;;
            test)
                HEALTH_URL="https://test.lifeverse.com/api/actuator/health"
                ;;
            prod)
                HEALTH_URL="https://lifeverse.com/api/actuator/health"
                ;;
        esac
    fi
}

# 基础健康检查
basic_health_check() {
    local attempt=1
    local start_time=$(date +%s)
    
    log "执行基础健康检查: $HEALTH_URL"
    
    while [[ $attempt -le $RETRIES ]]; do
        if [[ "$VERBOSE" == true ]]; then
            log "尝试 $attempt/$RETRIES..."
        fi
        
        local response
        local http_code
        local response_time
        
        # 执行HTTP请求
        response=$(curl -s -w "%{http_code}|%{time_total}" \
            --max-time "$TIMEOUT" \
            --connect-timeout 10 \
            "$HEALTH_URL" 2>/dev/null || echo "000|0")
        
        http_code=$(echo "$response" | cut -d'|' -f2)
        response_time=$(echo "$response" | cut -d'|' -f3)
        response_body=$(echo "$response" | cut -d'|' -f1)
        
        if [[ "$http_code" == "200" ]]; then
            local end_time=$(date +%s)
            local total_time=$((end_time - start_time))
            
            if [[ "$JSON_OUTPUT" == true ]]; then
                echo "{\"status\":\"UP\",\"http_code\":$http_code,\"response_time\":$response_time,\"total_time\":$total_time,\"attempts\":$attempt}"
            else
                success "健康检查通过 (尝试 $attempt/$RETRIES, 响应时间: ${response_time}s, 总耗时: ${total_time}s)"
            fi
            return 0
        else
            if [[ "$VERBOSE" == true ]]; then
                warning "健康检查失败 (HTTP $http_code, 响应时间: ${response_time}s)"
            fi
        fi
        
        if [[ $attempt -lt $RETRIES ]]; then
            sleep "$INTERVAL"
        fi
        ((attempt++))
    done
    
    local end_time=$(date +%s)
    local total_time=$((end_time - start_time))
    
    if [[ "$JSON_OUTPUT" == true ]]; then
        echo "{\"status\":\"DOWN\",\"http_code\":$http_code,\"response_time\":$response_time,\"total_time\":$total_time,\"attempts\":$attempt}"
    else
        error "健康检查失败，已尝试 $RETRIES 次 (总耗时: ${total_time}s)"
    fi
    return 1
}

# 深度健康检查
deep_health_check() {
    log "执行深度健康检查..."
    
    local health_details
    health_details=$(curl -s --max-time "$TIMEOUT" "${HEALTH_URL%/health}/health" 2>/dev/null || echo "{}")
    
    if [[ -z "$health_details" || "$health_details" == "{}" ]]; then
        error "无法获取详细健康信息"
        return 1
    fi
    
    # 检查各个组件状态
    local overall_status
    overall_status=$(echo "$health_details" | jq -r '.status // "UNKNOWN"' 2>/dev/null || echo "UNKNOWN")
    
    if [[ "$overall_status" != "UP" ]]; then
        error "系统整体状态异常: $overall_status"
        return 1
    fi
    
    # 检查数据库状态
    local db_status
    db_status=$(echo "$health_details" | jq -r '.components.db.status // "UNKNOWN"' 2>/dev/null || echo "UNKNOWN")
    
    if [[ "$db_status" != "UP" ]]; then
        error "数据库状态异常: $db_status"
        return 1
    fi
    
    # 检查Redis状态
    local redis_status
    redis_status=$(echo "$health_details" | jq -r '.components.redis.status // "UNKNOWN"' 2>/dev/null || echo "UNKNOWN")
    
    if [[ "$redis_status" != "UP" ]]; then
        error "Redis状态异常: $redis_status"
        return 1
    fi
    
    # 检查磁盘空间
    local disk_status
    disk_status=$(echo "$health_details" | jq -r '.components.diskSpace.status // "UNKNOWN"' 2>/dev/null || echo "UNKNOWN")
    
    if [[ "$disk_status" != "UP" ]]; then
        warning "磁盘空间状态异常: $disk_status"
    fi
    
    if [[ "$JSON_OUTPUT" == true ]]; then
        echo "$health_details"
    else
        success "深度健康检查通过"
        log "  - 系统状态: $overall_status"
        log "  - 数据库状态: $db_status"
        log "  - Redis状态: $redis_status"
        log "  - 磁盘状态: $disk_status"
    fi
    
    return 0
}

# 性能指标检查
performance_check() {
    log "执行性能指标检查..."
    
    local metrics_url="${HEALTH_URL%/health}/metrics"
    local metrics
    metrics=$(curl -s --max-time "$TIMEOUT" "$metrics_url" 2>/dev/null || echo "{}")
    
    if [[ -z "$metrics" || "$metrics" == "{}" ]]; then
        warning "无法获取性能指标"
        return 0
    fi
    
    # 检查JVM内存使用率
    local jvm_memory_used
    local jvm_memory_max
    jvm_memory_used=$(echo "$metrics" | jq -r '.["jvm.memory.used"] // 0' 2>/dev/null || echo "0")
    jvm_memory_max=$(echo "$metrics" | jq -r '.["jvm.memory.max"] // 1' 2>/dev/null || echo "1")
    
    local memory_usage_percent
    memory_usage_percent=$(echo "scale=2; $jvm_memory_used * 100 / $jvm_memory_max" | bc 2>/dev/null || echo "0")
    
    # 检查HTTP请求指标
    local http_requests_total
    local http_requests_error
    http_requests_total=$(echo "$metrics" | jq -r '.["http.server.requests.count"] // 0' 2>/dev/null || echo "0")
    http_requests_error=$(echo "$metrics" | jq -r '.["http.server.requests.error.count"] // 0' 2>/dev/null || echo "0")
    
    local error_rate
    if [[ "$http_requests_total" -gt 0 ]]; then
        error_rate=$(echo "scale=4; $http_requests_error * 100 / $http_requests_total" | bc 2>/dev/null || echo "0")
    else
        error_rate="0"
    fi
    
    # 检查数据库连接池
    local db_connections_active
    local db_connections_max
    db_connections_active=$(echo "$metrics" | jq -r '.["hikaricp.connections.active"] // 0' 2>/dev/null || echo "0")
    db_connections_max=$(echo "$metrics" | jq -r '.["hikaricp.connections.max"] // 1' 2>/dev/null || echo "1")
    
    local db_usage_percent
    db_usage_percent=$(echo "scale=2; $db_connections_active * 100 / $db_connections_max" | bc 2>/dev/null || echo "0")
    
    if [[ "$JSON_OUTPUT" == true ]]; then
        echo "{\"memory_usage_percent\":$memory_usage_percent,\"error_rate\":$error_rate,\"db_usage_percent\":$db_usage_percent,\"http_requests_total\":$http_requests_total}"
    else
        success "性能指标检查完成"
        log "  - JVM内存使用率: ${memory_usage_percent}%"
        log "  - HTTP错误率: ${error_rate}%"
        log "  - 数据库连接池使用率: ${db_usage_percent}%"
        log "  - HTTP请求总数: $http_requests_total"
    fi
    
    # 性能告警检查
    local performance_issues=0
    
    if (( $(echo "$memory_usage_percent > 85" | bc -l) )); then
        warning "JVM内存使用率过高: ${memory_usage_percent}%"
        ((performance_issues++))
    fi
    
    if (( $(echo "$error_rate > 5" | bc -l) )); then
        warning "HTTP错误率过高: ${error_rate}%"
        ((performance_issues++))
    fi
    
    if (( $(echo "$db_usage_percent > 80" | bc -l) )); then
        warning "数据库连接池使用率过高: ${db_usage_percent}%"
        ((performance_issues++))
    fi
    
    if [[ $performance_issues -gt 0 ]]; then
        warning "发现 $performance_issues 个性能问题"
        return 1
    fi
    
    return 0
}

# 容器健康检查
container_health_check() {
    log "执行容器健康检查..."
    
    local compose_file
    case $ENVIRONMENT in
        dev)
            compose_file="docker-compose.dev.yml"
            ;;
        test)
            compose_file="docker-compose.test.yml"
            ;;
        prod)
            compose_file="docker-compose.prod.yml"
            ;;
    esac
    
    if [[ ! -f "$compose_file" ]]; then
        warning "未找到Docker Compose文件: $compose_file"
        return 0
    fi
    
    # 检查容器状态
    local container_status
    container_status=$(docker-compose -f "$compose_file" ps --format json 2>/dev/null || echo "[]")
    
    if [[ "$container_status" == "[]" ]]; then
        error "未找到运行中的容器"
        return 1
    fi
    
    local unhealthy_containers=0
    local total_containers=0
    
    # 解析容器状态
    while IFS= read -r container; do
        if [[ -n "$container" ]]; then
            local name
            local state
            name=$(echo "$container" | jq -r '.Name // "unknown"' 2>/dev/null || echo "unknown")
            state=$(echo "$container" | jq -r '.State // "unknown"' 2>/dev/null || echo "unknown")
            
            ((total_containers++))
            
            if [[ "$state" != "running" ]]; then
                warning "容器状态异常: $name ($state)"
                ((unhealthy_containers++))
            elif [[ "$VERBOSE" == true ]]; then
                log "容器状态正常: $name ($state)"
            fi
        fi
    done <<< "$(echo "$container_status" | jq -c '.[]' 2>/dev/null || echo "")"
    
    if [[ "$JSON_OUTPUT" == true ]]; then
        echo "{\"total_containers\":$total_containers,\"unhealthy_containers\":$unhealthy_containers}"
    else
        if [[ $unhealthy_containers -eq 0 ]]; then
            success "容器健康检查通过 ($total_containers 个容器)"
        else
            error "容器健康检查失败 ($unhealthy_containers/$total_containers 个容器异常)"
        fi
    fi
    
    return $unhealthy_containers
}

# 网络连通性检查
network_connectivity_check() {
    log "执行网络连通性检查..."
    
    local endpoints=(
        "mysql:3306"
        "redis:6379"
        "kafka:9092"
    )
    
    local failed_endpoints=0
    
    for endpoint in "${endpoints[@]}"; do
        local host
        local port
        host=$(echo "$endpoint" | cut -d':' -f1)
        port=$(echo "$endpoint" | cut -d':' -f2)
        
        if timeout 5 bash -c "</dev/tcp/$host/$port" 2>/dev/null; then
            if [[ "$VERBOSE" == true ]]; then
                log "网络连接正常: $endpoint"
            fi
        else
            warning "网络连接失败: $endpoint"
            ((failed_endpoints++))
        fi
    done
    
    if [[ "$JSON_OUTPUT" == true ]]; then
        echo "{\"total_endpoints\":${#endpoints[@]},\"failed_endpoints\":$failed_endpoints}"
    else
        if [[ $failed_endpoints -eq 0 ]]; then
            success "网络连通性检查通过"
        else
            warning "网络连通性检查发现 $failed_endpoints 个问题"
        fi
    fi
    
    return $failed_endpoints
}

# 主函数
main() {
    # 创建日志目录
    mkdir -p "$(dirname "$LOG_FILE")"
    
    if [[ "$JSON_OUTPUT" != true ]]; then
        log "LifeVerse Platform 健康检查脚本启动"
    fi
    
    parse_args "$@"
    setup_environment
    
    local check_results=()
    local overall_status=0
    
    # 执行基础健康检查
    if basic_health_check; then
        check_results+=("basic:PASS")
    else
        check_results+=("basic:FAIL")
        overall_status=1
    fi
    
    # 执行深度检查
    if [[ "$DEEP_CHECK" == true ]]; then
        if deep_health_check; then
            check_results+=("deep:PASS")
        else
            check_results+=("deep:FAIL")
            overall_status=1
        fi
        
        if performance_check; then
            check_results+=("performance:PASS")
        else
            check_results+=("performance:WARN")
        fi
        
        if container_health_check; then
            check_results+=("container:PASS")
        else
            check_results+=("container:FAIL")
            overall_status=1
        fi
        
        if network_connectivity_check; then
            check_results+=("network:PASS")
        else
            check_results+=("network:WARN")
        fi
    fi
    
    # 输出最终结果
    if [[ "$JSON_OUTPUT" == true ]]; then
        local results_json="["
        for result in "${check_results[@]}"; do
            local check_name
            local check_status
            check_name=$(echo "$result" | cut -d':' -f1)
            check_status=$(echo "$result" | cut -d':' -f2)
            results_json+="{\"check\":\"$check_name\",\"status\":\"$check_status\"},"
        done
        results_json="${results_json%,}]"
        
        echo "{\"overall_status\":$overall_status,\"environment\":\"$ENVIRONMENT\",\"timestamp\":\"$(date -Iseconds)\",\"checks\":$results_json}"
    else
        if [[ $overall_status -eq 0 ]]; then
            success "所有健康检查通过"
        else
            error "健康检查发现问题"
        fi
        
        log "检查结果汇总:"
        for result in "${check_results[@]}"; do
            log "  - $result"
        done
    fi
    
    exit $overall_status
}

# 信号处理
trap 'error "健康检查被中断"; exit 130' INT TERM

# 执行主函数
main "$@"